package customer

import (
	"context"
	"fmt"
	"go.manyji.com/lib/log"
	"go.manyji.com/lib/util/errors"
	"sieve_admin_server/app/dao/daily_recharge"
	pkgCron "sieve_admin_server/pkg/cron"
	pkgTime "sieve_admin_server/pkg/time"
	"strings"
	"sync"
	"time"
)

var (
	dailyRechargeCronOnce = sync.Once{}
	dailyRechargeCron     *pkgCron.Cron
)

func (a *DailyRechargeSrv) init() error {

	var (
		initCount = 1
		wp        = sync.WaitGroup{}
		logMsg    []string
	)

	wp.Add(initCount)
	go func() {
		err := a.updateRechargeStatistics(time.Date(2023, 4, 1, 0, 0, 0, 0, time.Local))
		logMsg = append(logMsg, fmt.Sprintf("%+v", err))
		wp.Done()
	}()

	wp.Wait()
	return errors.New(strings.Join(logMsg, ","))
}

func (a *DailyRechargeSrv) Cron() error {

	dailyRechargeCronOnce.Do(func() {
		dailyRechargeCron = pkgCron.New(pkgCron.WithLocation(time.Local))
		log.Info(fmt.Sprintf("%v", a.init()))

		var (
			scheduleJobList = []struct {
				Spec    string
				Comment string
				pkgCron.FuncJob
			}{
				{
					// 同步搜索表
					Spec: "30 0 * * *",
					//Spec: "@every 12h",
					//Spec:    "@every 10s",
					Comment: "每天凌晨0点30分执行",
					//Comment: "每小时执行一次",
					FuncJob: a.UpdateRechargeStatistics,
				},
			}
		)

		for _, v := range scheduleJobList {
			_, _ = dailyRechargeCron.AddFunc(v.Spec, v.FuncJob)
		}

		dailyRechargeCron.Run()
	})

	return nil
}

func (a *DailyRechargeSrv) UpdateRechargeStatistics(args ...interface{}) {

	log.Info(fmt.Sprintf("%v", a.updateRechargeStatistics(args...)))
}

func (a *DailyRechargeSrv) updateRechargeStatistics(args ...interface{}) error {

	type columnType struct {
		LeaderId            *int64  `json:"leader_id"`
		LeaderName          *string `json:"leader_name"`
		AccountId           int64   `json:"account_id"`
		RechargePointsTotal uint64  `json:"recharge_points_total"`
		BonusPointsTotal    uint64  `json:"bonus_points_total"`
	}

	var (
		t           = time.Now()
		condition   = " GROUP BY account_id,creator"
		startDate   = time.Date(t.Year(), t.Month(), t.Day(), 0, 0, 0, 0, time.Local)
		endDate     = startDate.AddDate(0, 0, 1)
		leftJoinSQL = fmt.Sprintf("INNER JOIN (%v) leader_user ON leader_user.id = recharge_statistics_users.creator", fmt.Sprintf(`
			SELECT 
				id as id,
				id as leader_id,
				account as leader_account
			FROM 
				user
			GROUP BY id,account
`))
	)

	if len(args) == 1 {
		startDate = args[0].(time.Time)
	}
	if len(args) == 2 {
		startDate, condition = args[0].(time.Time), fmt.Sprintf("AND account_id = %v", args[1].(uint64))+condition
	}

	for now := startDate; !now.After(endDate); now = now.AddDate(0, 0, 1) {
		var (
			start = time.Date(now.Year(), now.Month(), now.Day()-1, 0, 0, 0, 0, now.Location()).Unix()
			end   = time.Date(now.Year(), now.Month(), now.Day(), 0, 0, 0, 0, now.Location()).Unix()

			querySQL = fmt.Sprintf(`
		SELECT
			leader_user.leader_id AS leader_id,
			leader_user.leader_account AS leader_name,
			recharge_statistics_users.account_id AS account_id,
			recharge_statistics_users.recharge_points_total,
			recharge_statistics_users.bonus_points_total
		FROM (
			SELECT
				account_id,
				creator,
				SUM(recharge_points) AS recharge_points_total,
				SUM(bonus_points) AS bonus_points_total
			FROM recharge
				WHERE recharge.create_at >= %v AND recharge.create_at <= %v
		    %v
		) recharge_statistics_users
		%v
	`, start, end, condition, leftJoinSQL)
		)

		log.Info(fmt.Sprintf("start:%v end:%v sql:%+v", pkgTime.Format(start), pkgTime.Format(end), querySQL))

		req, err := a.DailyRechargeRepo.QueryRaw(context.Background(), querySQL, columnType{})
		if err != nil {
			return err
		}

		for _, v := range req {

			vv := v.(*columnType)
			var leaderId int64
			var leaderName string
			if vv.LeaderId != nil {
				leaderId = *vv.LeaderId
			}
			if vv.LeaderName != nil {
				leaderName = *vv.LeaderName
			}
			var (
				entity = daily_recharge.DailyRechargeStatistics{}
				startD = time.Unix(start, 0)
				date   = fmt.Sprintf("%04v-%02v-%02v", startD.Year(), int(startD.Month()), startD.Day())
				item   = map[string]interface{}{
					"date":                  date,
					"recharge_points_total": vv.RechargePointsTotal,
					"bonus_points_total":    vv.BonusPointsTotal,
					"account_id":            vv.AccountId,
					"leader_id":             leaderId,
					"leader_name":           leaderName,
					"create_at":             now.Unix(),
					"updated_at":            now.Unix(),
				}
				checkDupSQL = fmt.Sprintf(`
			SELECT 
			    * 
			FROM %v
			WHERE
			     leader_id = %v AND account_id = %v AND date = '%v'
`, entity.TableName(), leaderId, vv.AccountId, date)
			)

			log.Info(fmt.Sprintf("date:%v check dup sql:%+v", date, checkDupSQL))

			req, err = a.DailyRechargeRepo.QueryRaw(context.Background(), checkDupSQL, entity)
			if err != nil {
				log.Err("create daily recharge err:%+v", err)
				continue
			}

			if req == nil {
				if err := a.DailyRechargeRepo.Create(context.Background(), item); err != nil {
					log.Err("create daily recharge err:%+v", err)
				}
				continue
			}

			s := req[0].(*daily_recharge.DailyRechargeStatistics)
			if s.RechargePointsTotal == vv.RechargePointsTotal && s.BonusPointsTotal == vv.BonusPointsTotal {
				continue
			}

			var (
				queries = map[string]interface{}{
					"id": s.ID,
				}
				updateKeys = map[string]interface{}{
					"recharge_points_total": vv.RechargePointsTotal,
					"bonus_points_total":    vv.BonusPointsTotal,
					"leader_name":           leaderName,
					"updated_at":            now.Unix(),
				}
			)

			if err := a.DailyRechargeRepo.Update(context.Background(), updateKeys, queries); err != nil {
				log.Err("update daily recharge err:%+v", err)
			}
		}
	}

	return nil
}
